﻿Imports System.Xml
''' <summary>
''' 数据检索器
''' </summary>
''' <remarks></remarks>
Public Class clsDataAssist
    ''' <summary>
    ''' 数据检索用HashTable
    ''' </summary>
    ''' <remarks></remarks>
    Private Shared DataItemTable As New Dictionary(Of String, List(Of XmlElement))
    ''' <summary>
    ''' WorkStorage的纯数据树
    ''' </summary>
    ''' <remarks></remarks>
    Private Shared WorkStorageTree As XmlNode
    ''' <summary>
    ''' 生成WORK-STORAGE数据检索用Hash表
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Sub GenernateSearchTable()
        WorkStorageTree = Nothing
        WorkStorageTree = mXmlDocument.CreateElement("WorkStorage")
        DataItemTable.Clear()
        For Each subDataNode As XmlNode In mDataNode.WorkStorageList
            DistanceFromRoot = 0
            Dim ReturnNode As XmlNode = GetDataItemOnly(subDataNode)
            If Not ReturnNode Is Nothing Then WorkStorageTree.AppendChild(ReturnNode)
        Next
        '将所有叶子信息放入检索表中
        '可以通过名字快速查找到元素，通过Parents得到父节点，父节点包含了这个节点的完整信息。。。
        For Each dataItem As XmlElement In WorkStorageTree.SelectNodes("//DataItem")
            '使用XPATH来获得所有DataItem的数据项目
            Dim DataName As String = dataItem.GetAttribute("NAME")
            If DataItemTable.ContainsKey(DataName) Then
                Dim DataInfo As List(Of XmlElement) = DataItemTable(DataName)
                DataInfo.Add(dataItem)
            Else
                Dim DataInfo As New List(Of XmlElement)
                DataInfo.Add(dataItem)
                DataItemTable.Add(DataName, DataInfo)
            End If
        Next
    End Sub
    ''' <summary>
    ''' 计算从根节点到当前节点距离
    ''' </summary>
    ''' <remarks></remarks>
    Private Shared DistanceFromRoot As Integer
    ''' <summary>
    ''' 获取纯数据元素
    ''' </summary>
    ''' <param name="DataNode"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Shared Function GetDataItemOnly(ByVal DataNode As XmlElement) As XmlNode
        Dim ItemNode As XmlElement = Nothing
        Select Case True
            Case DataNode.Name = "COMMENTLIST"
                ItemNode = Nothing
            Case DataNode.Name = "MACRO"
                ItemNode = Nothing
            Case DataNode.Name = "INCLUDE"
                'COPY句的情况
                Dim XmlReader As New XmlDocument()
                Dim CopyBookName As String = DataNode.GetAttribute("COPYBOOKNAME")
                If CommonMethod.mCopyBookInfoDic.Item(CopyBookName).CopyBookType = enmCopyBookType.Procedure Then Return Nothing
                Dim xmlFileName As String = MyConfig.CopyXMLFolder & CopyBookName & ".xml"
                ItemNode = mXmlDocument.CreateElement("ParentItem")
                If IO.File.Exists(xmlFileName) Then
                    XmlReader.Load(xmlFileName)
                    For Each subDataNode As XmlNode In XmlReader.FirstChild.ChildNodes
                        Dim ReturnNode As XmlNode = GetDataItemOnly(subDataNode)
                        If Not ReturnNode Is Nothing Then
                            ItemNode.AppendChild(ReturnNode)
                        End If
                    Next
                End If
            Case DataNode.GetAttribute("TYPE") <> String.Empty
                '由于TYPE = COPYBOOK 所以这里需要变换一下INCLUDE和TYPE的代码书写位置
                ItemNode = mXmlDocument.CreateElement("DataItem")
                For Each attr As XmlAttribute In DataNode.Attributes
                    ItemNode.SetAttribute(attr.Name, attr.Value)
                Next
                ItemNode.SetAttribute("Distance", DistanceFromRoot)
                DistanceFromRoot += clsDataObject.GetUsageByXmlElement(ItemNode)
            Case DataNode.HasChildNodes
                ItemNode = mXmlDocument.CreateElement("ParentItem")
                For Each attr As XmlAttribute In DataNode.Attributes
                    ItemNode.SetAttribute(attr.Name, attr.Value)
                Next
                For Each subDataNode As XmlNode In DataNode.ChildNodes
                    Dim ReturnNode As XmlNode = GetDataItemOnly(subDataNode)
                    If Not ReturnNode Is Nothing Then
                        If subDataNode.Name = "INCLUDE" Then
                            'COPY句的时候，直接将COPY句的内容追加到节点即可
                            For Each subInclude As XmlNode In ReturnNode.ChildNodes
                                ItemNode.AppendChild(subInclude.Clone)
                            Next
                        Else
                            ItemNode.AppendChild(ReturnNode)
                        End If
                    End If
                Next
        End Select
        Return ItemNode
    End Function
    ''' <summary>
    ''' 通过数据名称获得数据节点
    ''' </summary>
    ''' <param name="DataName"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function GetDataItemByDataName(ByVal DataName As String) As XmlElement
        '这里的DataName是原始的数据，没有经过变量名称变换
        If DataName.Contains("(") And DataName.EndsWith(")") Then
            DataName = Mid(DataName, 1, DataName.IndexOf("("))
        End If
        Dim resultXml As List(Of XmlElement) = Nothing
        If DataItemTable.TryGetValue(DataName, resultXml) Then
            If resultXml.Count = 1 Then
                Return resultXml.Item(0)
            End If
        End If
        Return Nothing
    End Function
    ''' <summary>
    ''' 通过数据名称获得数据节点
    ''' </summary>
    ''' <param name="DataName"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function GetRootItemByDataName(ByVal DataName As String) As XmlElement
        '这里的DataName是原始的数据，没有经过变量名称变换
        If DataName.Contains("(") And DataName.EndsWith(")") Then
            DataName = Mid(DataName, 1, DataName.IndexOf("("))
        End If
        Dim resultXml As List(Of XmlElement) = Nothing
        For Each mNode As XmlElement In WorkStorageTree
            If mNode.GetAttribute("NAME") = DataName Then
                Return mNode
            End If
        Next
        Return Nothing
    End Function
    ''' <summary>
    ''' 通过数据路径获得数据节点
    ''' </summary>
    ''' <param name="DataPath"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function GetDataItemByDataPath(ByVal DataPath As String) As XmlElement
        Dim resultXml As List(Of XmlElement) = Nothing
        Dim PathArray As String() = DataPath.Split(".")
        If DataItemTable.TryGetValue(PathArray(PathArray.Length - 1), resultXml) Then
            If resultXml.Count = 1 Then
                Return resultXml.Item(0)
            Else
                '遍历所有项目
                For Each TestItem As XmlElement In resultXml
                    Dim RtnItem As XmlNode = TestItem
                    '从下而上匹配整个路径
                    'PathArray是离叶子最近的路径，0是Path的根路径
                    Dim IsPass As Boolean = False
                    For TestLv As Byte = 0 To PathArray.Length - 2
                        Do While Not TestItem.ParentNode Is Nothing
                            If CType(TestItem.ParentNode, XmlElement).GetAttribute("NAME") = PathArray(PathArray.Length - TestLv - 2) Then
                                '如果有匹配的项目，则跳出WHILE条件
                                TestItem = TestItem.ParentNode
                                If TestLv = PathArray.Length - 2 Then
                                    IsPass = True
                                End If
                                Exit Do
                            Else
                                TestItem = TestItem.ParentNode
                            End If
                        Loop
                    Next
                    If IsPass Then
                        Return RtnItem
                    End If
                Next
            End If
        End If
        Return Nothing
    End Function
End Class
